﻿using System.ComponentModel;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using HiSport.Core.Entity.Bas;
using HiSport.Core.Entity.Order;
using HiSportApplet.Application.Common.SqlSugar;
using HiSportApplet.Application.Service.Function.ReserveSiteManagement.Dtos;
using HiSportApplet.Application.Service.Order.OrderSiteManagement.Dtos;
using HiSportApplet.Core.Entity.Bas;
using HiSportApplet.Core.Entity.Orders;
using HiSportApplet.Core.Enum;
using Microsoft.AspNetCore.Mvc;
using Senparc.Weixin.Open.WxaAPIs.SecOrder;
using Yitter.IdGenerator;

namespace HiSportApplet.Application.Service.Function.ReserveSiteManagement.Service
{
    /// <summary>
    /// 预定场地
    /// </summary>
    [ApiDescriptionSettings("业务管理", Tag = "场地业务", SplitCamelCase = false)]
    public class ScheduledSiteService : ITransient, IDynamicApiController, IScheduledSiteService
    {
        /// <summary>
        /// 场地
        /// </summary>
        private readonly SqlSugarRepository<BasSite> _basSiteRep;

        private readonly SqlSugarRepository<BasSiteType> _basSiteType;

        private readonly SqlSugarRepository<BaseSiteLock> _baseSiteLock;

        /// <summary>
        /// 订单主表
        /// </summary>
        private readonly SqlSugarRepository<OrderSite> _orderSite;

        /// <summary>
        /// 订单子表
        /// </summary>
        private readonly SqlSugarRepository<OrderSiteInfo> _orderSiteInfo;

        /// <summary>
        /// 固定 订单主表
        /// </summary>
        private readonly SqlSugarRepository<OrderFixeSite> _orderFixeSite;

        /// <summary>
        /// 固定 订单子表
        /// </summary>
        private readonly SqlSugarRepository<OrderFixeSiteInfo> _orderFixeSiteInfo;

        /// <summary>
        ///场地计费规则
        /// </summary>
        private readonly SqlSugarRepository<BasSiteBillingRule> _basSiteBillingRule;

        /// <summary>
        ///计费规则
        /// </summary>
        private readonly SqlSugarRepository<BasBillingRule> _basBillingRule;

        /// <summary>
        ///计费规则详情
        /// </summary>
        private readonly SqlSugarRepository<BasBillingRuleInfo> _basBillingRuleInfo;

        public ScheduledSiteService(SqlSugarRepository<BasSite> basSiteRep,
            SqlSugarRepository<BaseSiteLock> baseSiteLock,
            SqlSugarRepository<OrderSite> orderSite,
            SqlSugarRepository<OrderSiteInfo> orderSiteInfo,
            SqlSugarRepository<OrderFixeSite> orderFixeSite,
            SqlSugarRepository<OrderFixeSiteInfo> orderFixeSiteInfo,
            SqlSugarRepository<BasSiteType> basSiteType,
            SqlSugarRepository<BasSiteBillingRule> basSiteBillingRule,
            SqlSugarRepository<BasBillingRule> basBillingRule,
            SqlSugarRepository<BasBillingRuleInfo> billingRuleInfo)
        {
            _basSiteRep = basSiteRep;
            _baseSiteLock = baseSiteLock;
            _orderSite = orderSite;
            _orderSiteInfo = orderSiteInfo;
            _basSiteType = basSiteType;
            _orderFixeSite = orderFixeSite;
            _orderFixeSiteInfo = orderFixeSiteInfo;
            _basSiteBillingRule = basSiteBillingRule;
            _basBillingRule = basBillingRule;
            _basBillingRuleInfo = billingRuleInfo;
        }

        /// <summary>
        /// 获取预定场地详细信息
        /// </summary>
        [HttpPost]
        [DisplayName("获取订场信息")]
        public async Task<List<ScheduledSiteDto>> GetScheduledSiteInfoList(DestinedSiteInputDto inputDto)
        {
            var result = new List<ScheduledSiteDto>();

            //查询场地类型
            var siteType = await _basSiteType.AsQueryable()
                .Where(x => x.Id == inputDto.SiteTypeId)
                .FirstAsync();
            if (siteType == null)
            {
                throw Oops.Oh($"没有查询到此场地类型");
            }


            //获取类型下的所有场地
            var siteList = await _basSiteRep.AsQueryable()
                .Where(x => x.SiteTypeId == inputDto.SiteTypeId)
                .ToListAsync();
            var siteIds = siteList.Select(x => x.Id);


            //被锁定的订单
            var siteLock = await _baseSiteLock.AsQueryable()
                .Where(x => siteIds.Contains(x.SiteId)
                            && x.LockTime.Date == inputDto.ScheduledTime.Date)
                .ToListAsync();

            //预定订单
            var orderSiteInfo = await _orderSiteInfo.AsQueryable()
                .Where(x => siteIds.Contains(x.SiteId)
                && x.ScheduledTime.Date == inputDto.ScheduledTime.Date)
                .ToListAsync();

            //预定订单
            var orderSiteId = orderSiteInfo.GroupBy(x => x.OrderSiteId).Select(x => x.Key).ToList();
            var orderSite = await _orderSite.AsQueryable().Where(x => orderSiteId.Contains(x.Id)).ToListAsync();



            //固定 预定订单详情
            var fixedOrderInfo = await _orderFixeSiteInfo.AsQueryable()
                .Where(x => siteIds.Contains(x.SiteId)
                            && x.OrderState != OrderStateEnum.AllCancel
                            && x.FixeSiteScheduledTime.Date == inputDto.ScheduledTime.Date)
                .ToListAsync();

            //固定 预定订单
            var fixedOrderId = fixedOrderInfo.GroupBy(x => x.OrderFixeSiteId).Select(x => x.Key).ToList();
            var fixedOrder = await _orderFixeSite.AsQueryable().Where(x => fixedOrderId.Contains(x.Id)).ToListAsync();

            //获取场地看板的时间表详情
            result = await GetSiteKanbanTimeInfo(inputDto.ScheduledTime, siteType, siteList, siteLock, orderSiteInfo, orderSite, fixedOrderInfo, fixedOrder);

            return result;
        }


        /// <summary>
        /// 获取预定场地的状态
        /// </summary>
        /// <param name="orderSite"></param>
        /// <param name="orderSiteInfo"></param>
        /// <param name="siteLock"></param>
        /// <returns></returns>
        private async Task<SiteInfoDto> GetScheduledOrderInfo(OrderSite orderSite, OrderSiteInfo? orderSiteInfo, OrderFixeSite orderFixeSite, OrderFixeSiteInfo orderFixeSiteInfo, BaseSiteLock? siteLock)
        {

            //锁定状态
            if (siteLock != null)
            {

                return await Task.FromResult(new SiteInfoDto()
                {
                    Id = siteLock.Id,
                    State = ScheduledSiteStateEnum.Lock,
                });
            }

            //预定订单状态
            if (orderSiteInfo != null)
            {
                return await Task.FromResult(new SiteInfoDto()
                {
                    Id = orderSiteInfo.Id,
                    MemberId = orderSite?.MemberId ?? 0,
                    OrderId = orderSite?.Id ?? 0,
                    OrderRemark = orderSite?.Remark,
                    MemberName = orderSite?.MemberName,
                    Phone = orderSite?.Phone,
                    State = orderSiteInfo.ScheduledSiteState,
                });

            }

            //固定 预定订单状态
            if (orderFixeSiteInfo != null)
            {

                return await Task.FromResult(new SiteInfoDto()
                {
                    Id = orderFixeSiteInfo.Id,
                    MemberId = orderFixeSite?.MemberId ?? 0,
                    OrderId = orderFixeSite?.Id,
                    OrderRemark = orderFixeSite?.Remark,
                    Phone = orderFixeSite?.Phone,
                    State = orderFixeSiteInfo.ScheduledSiteState,
                });
            }

            return null;
        }


        /// <summary>
        /// 获取场地看板的时间表详情
        /// </summary>
        /// <param name="scheduledTime"></param>
        /// <param name="basSiteType"></param>
        /// <param name="siteList"></param>
        /// <param name="siteLock"></param>
        /// <param name="orderInfo"></param>
        /// <param name="order"></param>
        /// <param name="result"></param>
        private async Task<List<ScheduledSiteDto>> GetSiteKanbanTimeInfo(DateTime scheduledTime, BasSiteType basSiteType, List<BasSite> siteList, List<BaseSiteLock> siteLock,
            List<OrderSiteInfo> orderInfo, List<OrderSite> order, List<OrderFixeSiteInfo> orderFixeSiteInfo, List<OrderFixeSite> orderFixeSite)
        {
            var result = new List<ScheduledSiteDto>();

            //获取看板列表
            var kanbanTimeList = await GetKanbanTimeList(basSiteType.StartKanbanTime, basSiteType.EndKanbanTime, basSiteType.Interval);





            var weekStr = ((int)scheduledTime.DayOfWeek).ToString();



            var siteIdList = siteList.Select(x => x.Id).ToList();


            //查询场地的计费规则
            var billingRule = await _basSiteBillingRule.AsQueryable()
                .Where(x => siteIdList.Contains(x.SiteId) && x.Weeks.Contains(weekStr) && x.Status == StatusEnum.Enable)
                .OrderBy(x => x.Sort)
                .ToListAsync();

            var billingRuleId = billingRule.Select(x => x.BillingRuleId).ToList();

            billingRuleId = await _basBillingRule.AsQueryable()
                .Where(x => billingRuleId.Contains(x.Id) && x.Status == StatusEnum.Enable)
                .Select(x => x.Id)
                .ToListAsync();

            //2.查询计费规则
            var billingRuleInfoList = await _basBillingRuleInfo.AsQueryable()
                .Where(x => billingRuleId.Contains(x.BillingRuleId)).ToListAsync();



            foreach (var item in siteList)
            {
                var siteInfos = new List<SiteInfoDto>();

                foreach (var kanbanTime in kanbanTimeList)
                {
                    //查询当前锁
                    var thisSteLock = siteLock.FirstOrDefault(x =>
                        x.StartTime == kanbanTime[0] && x.EndTime == kanbanTime[1] && x.SiteId == item.Id);

                    //查询订单详情
                    var thisOrderInfo = orderInfo.FirstOrDefault(x =>
                        x.StartTime == kanbanTime[0] && x.EndTime == kanbanTime[1] && x.SiteId == item.Id);
                    //订单订单
                    var thisOrder = order.FirstOrDefault(x => x.Id == thisOrderInfo?.OrderSiteId);



                    //固定预定订单详情
                    var thisOrderFixeSiteInfo = orderFixeSiteInfo.FirstOrDefault(x =>
                        x.StartTime == kanbanTime[0] && x.EndTime == kanbanTime[1] && x.SiteId == item.Id);

                    //固定预定订单
                    var thisOrderFixeSite = orderFixeSite.FirstOrDefault(x => x.Id == thisOrderInfo?.OrderSiteId);

                    //当前状态
                    var ScheduledState = await GetScheduledOrderInfo(thisOrder, thisOrderInfo, thisOrderFixeSite, thisOrderFixeSiteInfo, thisSteLock);

                    var v1 = billingRule.Where(x => x.SiteId == item.Id).ToList();
                    var vid = billingRule.Select(x => x.BillingRuleId).ToList();
                    var v2 = billingRuleInfoList.Where(x => vid.Contains(x.BillingRuleId)).ToList();

                    siteInfos.Add(new SiteInfoDto()
                    {
                        Id = ScheduledState?.Id ?? YitIdHelper.NextId(),
                        Price = await GetSitePrice2(v1, v2, kanbanTime[0], kanbanTime[1]),
                        StartTime = kanbanTime[0],
                        EndTime = kanbanTime[1],
                        ScheduledTime = scheduledTime.Date,
                        MemberId = ScheduledState?.MemberId ?? 0,
                        Phone = ScheduledState?.Phone,
                        MemberName = ScheduledState?.MemberName,
                        OrderId = ScheduledState?.OrderId ?? 0,
                        OrderRemark = ScheduledState?.OrderRemark,
                        State = (Convert.ToDateTime($"{scheduledTime.Date:yyyy-MM-dd} {kanbanTime[1]}") < DateTime.Now) ? ScheduledSiteStateEnum.Expired : ScheduledState?.State ?? ScheduledSiteStateEnum.Bookable,
                    });

                }

                result.Add(new ScheduledSiteDto()
                {
                    ScheduledTime = scheduledTime.Date,
                    SiteId = item.Id,
                    SiteName = item.SiteName,
                    SiteTypeId = item.SiteTypeId,
                    SiteInfos = siteInfos,
                });
            }

            return result;
        }


        /// <summary>
        /// 获取看板时间列表
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        private Task<List<string[]>> GetKanbanTimeList(string startTime, string endTime, int interval)
        {
            var res = new List<string[]>();
            var startDateTime = Convert.ToDateTime($"{DateTime.Now.Date:yyyy-MM-dd} {startTime}");
            var endDateTime = Convert.ToDateTime($"{DateTime.Now.Date:yyyy-MM-dd} {endTime}");
            while (startDateTime < endDateTime)
            {
                string[] thisKanbanTime;
                switch (interval)
                {
                    case 60:
                        thisKanbanTime = new string[2];
                        thisKanbanTime[0] = $"{startDateTime.Hour}:{startDateTime.Minute.ToString().PadRight(2, '0')}";
                        startDateTime = startDateTime.AddHours(1);
                        thisKanbanTime[1] = $"{startDateTime.Hour}:{startDateTime.Minute.ToString().PadRight(2, '0')}";
                        res.Add(thisKanbanTime);

                        break;
                    case 30:
                        thisKanbanTime = new string[2];
                        thisKanbanTime[0] = $"{startDateTime.Hour}:{startDateTime.Minute.ToString().PadRight(2, '0')}";
                        startDateTime = startDateTime.AddMinutes(30);
                        thisKanbanTime[1] = $"{startDateTime.Hour}:{startDateTime.Minute.ToString().PadRight(2, '0')}";
                        res.Add(thisKanbanTime);

                        break;
                }
            }
            return Task.FromResult(res);

        }


        private async Task<decimal> GetSitePrice2(List<BasSiteBillingRule> billingRule, List<BasBillingRuleInfo> billingRuleInfoList, string startTime, string endTime)
        {

            foreach (var item in billingRule)
            {
                var infoList = billingRuleInfoList.Where(x => x.BillingRuleId == item.BillingRuleId);
                foreach (var info in infoList)
                {

                    var infoStartTime = Convert.ToDateTime(info.StartTime.ToString() + ":00");
                    var infoEndTime = Convert.ToDateTime("00:00");
                    if (info.EndTime == 24)
                    {
                        infoEndTime = Convert.ToDateTime("23:59");
                    }

                    //时间段类 符合的价格
                    if (Convert.ToDateTime(startTime) >= infoStartTime)
                    {
                        if (Convert.ToDateTime(endTime) <= infoEndTime)
                        {
                            return info.Price;
                        }
                    }
                }

            }

            return 0;
        }

        /// <summary>
        /// 场地检查（检查场地是 是都预定 或锁场）
        /// </summary>
        /// <returns></returns>
        public async Task SiteCheck(List<SiteCheckDto> InputDto)
        {
            foreach (var item in InputDto)
            {
                //检查是否预定
                var siteLock = await _baseSiteLock.AsQueryable()
                    .Where(x => x.LockTime.Date == item.Time.Date
                                && x.StartTime == item.StartTime
                                && x.EndTime == item.EndTime
                                && x.SiteId == item.SiteId).FirstAsync();
                if (siteLock != null)
                {
                    throw Oops.Oh($"【{item.Time.Date:yyyy-MM-dd} {item.StartTime}-{item.EndTime}】选中的场次中已被锁定");
                }

                //检查是否订场
                var orderSiteInfo = await _orderSiteInfo.AsQueryable()
                    .Where(x => x.ScheduledTime.Date == item.Time.Date
                                && x.StartTime == item.StartTime
                                && x.EndTime == item.EndTime
                                && x.SiteId == item.SiteId).FirstAsync();
                if (orderSiteInfo != null)
                {
                    throw Oops.Oh($"【{item.Time.Date:yyyy-MM-dd} {item.StartTime}-{item.EndTime}】选中的场次中已被预定");
                }

                //检查是否固定订场
                var orderFixeSiteInfo = await _orderFixeSiteInfo.AsQueryable()
                    .Where(x => x.FixeSiteScheduledTime.Date == item.Time.Date
                                && x.StartTime == item.StartTime
                                && x.EndTime == item.EndTime
                                && x.SiteId == item.SiteId).FirstAsync();
                if (orderFixeSiteInfo != null)
                {
                    throw Oops.Oh($"【{item.Time.Date:yyyy-MM-dd} {item.StartTime}-{item.EndTime}】选中的场次中已被固定预定");
                }


            }
        }
    }
}
